package com.glsc.ngateway.platform.service.owncloud;

import com.glsc.ngateway.common.api.platform.dto.owncloud.*;
import com.glsc.ngateway.common.api.platform.resp.PlatformResponse;
import com.glsc.ngateway.common.base.converter.platform.OwnCloudOperateLogConverter;
import com.glsc.ngateway.common.base.exception.PlatformException;
import com.glsc.ngateway.common.base.repo.mysql.gateway.platform.OwnCloudOperateLogRepo;
import com.glsc.ngateway.platform.utils.RequestTool;
import com.glsc.ngateway.platform.vo.SystemRelatedFileInfoVo;
import org.apache.logging.log4j.util.Strings;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * @author xuchang
 * 网盘相关接口切面以添加日志
 */
@Aspect
@Component
public class OwnCloudLogAspect {

    private final Logger logger = LoggerFactory.getLogger(OwnCloudLogAspect.class);

    public static final String OWNCLOUD_METHOD_QUERY = "query";

    @Resource
    private RequestTool requestTool;

    @Resource
    private OwnCloudOperateLogRepo logRepo;

    @Pointcut("@annotation(com.glsc.ngateway.platform.service.owncloud.OwnCloudLog)")
    public void webLog() {
    }

    @Around("webLog()")
    public Object aroundAdvice(ProceedingJoinPoint point) {
        Object result = null;
        try {
            result = point.proceed();
        } catch (PlatformException e) {
            addLog(point, e, null);
            throw e;
        } catch (Throwable e) {
            logger.error("异常", e);
            addLog(point, e, null);
            throw PlatformException.error(e.getMessage());
        }
        addLog(point, null, result);
        return result;
    }

    private void addLog(ProceedingJoinPoint point, Throwable e, Object result) {
        String operator = requestTool.getUserFromRequest().getUsername();
        OwnCloudOperateLogDto logDto = OwnCloudOperateLogDto.builder().operator(operator).createAccount(operator).updateAccount(operator).build();
        if (Objects.isNull(e)) {
            if (result instanceof PlatformResponse) {
                PlatformResponse response = (PlatformResponse) result;
                logDto.setResult(response.isSuccess() ? "SUCCESS" : "FAILED");
            } else if (result instanceof ResponseEntity) {
                ResponseEntity response = (ResponseEntity) result;
                logDto.setResult(response.getStatusCode().is2xxSuccessful() ? "SUCCESS" : "FAILED");
            } else {
                logDto.setResult("SUCCESS");
            }
        } else {
            logDto.setResult("FAILED");
            logDto.setErrInfo(e.getMessage());
        }
        Object[] args = point.getArgs();
        OwnCloudLog annotation = ((MethodSignature) point.getSignature()).getMethod().getAnnotation(OwnCloudLog.class);
        OwnCloudMethodEnum type = annotation.value();
        logDto.setType(type.getType());
        switch (type) {
            case OWNCLOUD_METHOD_QUERY:
                OwnCloudQueryParamDto queryParam = (OwnCloudQueryParamDto) Arrays.stream(args).filter(p -> p.getClass() == OwnCloudQueryParamDto.class).findAny()
                        .orElseThrow(() -> PlatformException.error("未匹配到OWNCLOUD_METHOD_QUERY参数类型, OwnCloudQueryParamDto:" +
                                        Arrays.stream(args).map(p -> p.getClass().getName()).collect(Collectors.joining(",")),
                                true, true));
                logDto.setLogInfo("查询系统-【" + queryParam.getOpName() + "】"
                        + (Strings.isNotBlank(queryParam.getFileName()) ? ", 名为【" + queryParam.getFileName() + "】的文档" : "关联文档"));
                break;
            case OWNCLOUD_METHOD_DOWNLOAD:
                OwnCloudDownloadParamDto downloadParam = (OwnCloudDownloadParamDto) Arrays.stream(args).filter(p -> p.getClass() == OwnCloudDownloadParamDto.class).findAny()
                        .orElseThrow(() -> PlatformException.error("未匹配到OWNCLOUD_METHOD_DOWNLOAD参数类型, OwnCloudDownloadParamDto:" +
                                        Arrays.stream(args).map(p -> p.getClass().getName()).collect(Collectors.joining(",")),
                                true, true));
                logDto.setLogInfo("下载" + (downloadParam.getIsDir() ? "文件夹" : "文件") + ":路径-【" + downloadParam.getUrl() + "】");
                break;
            case OWNCLOUD_METHOD_ADD:
                String url = (String) Arrays.stream(args).filter(p -> p.getClass() == String.class).findAny()
                        .orElseThrow(() -> PlatformException.error("未匹配到OWNCLOUD_METHOD_ADD参数类型, String:" +
                                        Arrays.stream(args).map(p -> p.getClass().getName()).collect(Collectors.joining(",")),
                                true, true));
                MultipartFile[] files = (MultipartFile[]) Arrays.stream(args).filter(p -> Objects.nonNull(p) && p.getClass().isArray() && p.getClass().getComponentType() == MultipartFile.class)
                        .findAny().orElse(null);
                logDto.setLogInfo(Objects.isNull(files) ? ("新建文件夹：【" + url + "】")
                        : ("在【" + url + "】上传文件：" + Arrays.stream(files).map(MultipartFile::getOriginalFilename).collect(Collectors.joining(","))));
                break;
            case OWNCLOUD_METHOD_RENAME:
                OwnCloudRenameParamDto renameParam = (OwnCloudRenameParamDto) Arrays.stream(args).filter(p -> p.getClass() == OwnCloudRenameParamDto.class).findAny()
                        .orElseThrow(() -> PlatformException.error("未匹配到OWNCLOUD_METHOD_RENAME参数类型, OwnCloudRenameParamDto:" +
                                        Arrays.stream(args).map(p -> p.getClass().getName()).collect(Collectors.joining(",")),
                                true, true));
                logDto.setLogInfo("重命名【" + renameParam.getUrl() + "】为【" + renameParam.getNewUrl() + "】");
                break;
            case OWNCLOUD_METHOD_DEL:
                OwnCloudDelParamDto delParam = (OwnCloudDelParamDto) Arrays.stream(args).filter(p -> p.getClass() == OwnCloudDelParamDto.class).findAny()
                        .orElseThrow(() -> PlatformException.error("未匹配到OWNCLOUD_METHOD_DEL参数类型, OwnCloudDelParamDto:" +
                                        Arrays.stream(args).map(p -> p.getClass().getName()).collect(Collectors.joining(",")),
                                true, true));
                logDto.setLogInfo("删除" + (delParam.getIsDir() ? "文件夹" : "文件") + "：【" + delParam.getUrl() + "】");
                break;
            case OWNCLOUD_METHOD_UPDATE_CONFIG:
                List<SystemRelatedFileInfoVo.FileInfoVo> updateConfigParam = (List<SystemRelatedFileInfoVo.FileInfoVo>) Arrays.stream(args)
                        .filter(p -> Objects.nonNull(p) && p.getClass() == ArrayList.class)
                        .findAny().orElse(null);
                logDto.setLogInfo("修改系统文件默认目录配置:" + updateConfigParam);
                break;
            case OWNCLOUD_METHOD_VALID_CONFIG:
                Boolean valid = (Boolean) Arrays.stream(args)
                        .filter(p -> Objects.nonNull(p) && p.getClass() == Boolean.class)
                        .findAny().orElse(null);
                logDto.setLogInfo((valid ? "【启动】" : "【禁用】") + "系统文件目录配置");
                break;
            case OWNCLOUD_METHOD_SYNC_SYSTEM_DIR:
                logDto.setLogInfo("按配置生成系统目录");
                break;
            default:
                throw PlatformException.error("未找到日志类型:" + type, true, true);
        }
        logRepo.save(OwnCloudOperateLogConverter.dto2Do(logDto));
    }
}
